﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CivLib.CivNum
{

  /// <summary>
  /// Interface for a soluable equation
  /// </summary>
  public interface ISoluableEqn
  {
    /// <summary>
    /// Accesses the variables in the equation
    /// </summary>
    /// <param name="i">index of the variable</param>
    /// <returns>the current variable value</returns>
    double this[int i] { get; set; }
    /// <summary>
    /// Gets the number of variables in the equation
    /// </summary>
    int Count { get; }
    /// <summary>
    /// Returns an array of bool that is 1 if the variable is constrianed
    /// and 0 if it is not
    /// </summary>
    bool[] Constrained { get; set; }
    /// <summary>
    /// Accesses an array of String that has the variable names
    /// </summary>
    string[] VarName { get; set; }
    /// <summary>
    /// Gets the current error in the equation with the variables as they are,
    /// when this reaches 0 the equation can be considered valid
    /// </summary>
    /// <returns>current error</returns>
    double Residual();
  }

  abstract class SolverBase
  {
    protected double m_tolerence = 0.0001;
    protected double m_maxIterations = 200;
    protected ISoluableEqn m_eqn;
    protected delegate double ErrorFunction();

    /// <summary>
    /// The tolerence the solver will use for stopping
    /// </summary>
    public double Tolerence
    {
      get { return m_tolerence; }
      set { m_tolerence = value; }
    }
    /// <summary>
    /// The maximum number of iterations
    /// </summary>
    public double MaxIterations
    {
      get { return m_maxIterations; }
      set { m_maxIterations = value; }
    }
    /// <summary>
    /// The equation to be solved
    /// </summary>
    public ISoluableEqn Equation
    {
      get { return m_eqn; }
      set { m_eqn = value; }
    }

    private SolverBase() { ;}

    public SolverBase(ISoluableEqn a_variables, double a_tolerance = 0.0001, double a_maxIter = 200)
    {
      m_eqn = a_variables;
      m_tolerence = a_tolerance;
      m_maxIterations = a_maxIter;
    }

    public abstract void Solve();
  }

  /// <summary>
  /// Exception that is thrown when a solver doens't work out
  /// </summary>
  public class SolverException : System.ApplicationException
  {
    /// <summary>
    /// Basic empty constructor
    /// </summary>
    public SolverException() :
      base() { }
    /// <summary>
    /// Constructor with a message
    /// </summary>
    /// <param name="message">message to add to exception</param>
    public SolverException(string message) :
      base(message) { }
    /// <summary>
    /// Constructor with a message and another exception embedded
    /// </summary>
    /// <param name="message">message</param>
    /// <param name="inner">exception contained</param>
    public SolverException(string message, System.Exception inner) :
      base(message, inner) { }
  }

}
